/****************************************************************************************************************************
 * @File name:gpio_i2c.c
 * @Author:sunshu
 * @Version:v1.00
 * @Date:2017/12/08
 * @Description:I2C master write or read the I2C slave.
 * @Others:
 * @Function List:
 1.void SCL_0(void):SCL=0;
 2.void SCL_1(void):SCL=1;
 3.void SDA_0(void):SDA=0;
 4.void SDA_1(void):SDA=1;
 5.unsigned char SDA_DATA(void):read the ACK of the slave;
 6.void I2C_Init(void):the initializations of the pins of the SCL and SDA;
 7.void I2C_Delay(void):delay a few microseconds;
 8.void I2C_Start(void):I2C start signal;
 9.void I2C_Stop(void):I2C stop signal;
 10.void I2C_SendAck(void):master send ACK to slave;
 11.void I2C_SendNoAck(void):master send no ACK to slave;
 12.unsigned char I2C_WaitAck(void):master wait for ACK from slave;
 13.unsigned char I2C_SendByte(unsigned char dat):master send a byte to slave;
 14.void I2C_RcvDat(unsigned char *pRdDat):master read a byte from slave;
 15.void I2C_ReceiveBytes(unsigned char *pBuffer,unsigned char bytes):master read a few bytes from slave.it is used in I2C_ReadData();
 16.unsigned char I2C_WriteData(unsigned char DeviceAddr, unsigned char RegisterAddr,unsigned char* pBuffer,unsigned int NumByte):master write bytes to slave;
 17.unsigned char I2C_ReadData(unsigned char DeviceAddr, unsigned char RegisterAddr,unsigned char* pBuffer,unsigned int NumByte):master read bytes from slave;
 * @History:
****************************************************************************************************************************/

#include "stm32f4xx_hal.h"
#include "i2c.h"

void I2C_Init(void);
unsigned char I2C_WriteData(unsigned char Port,unsigned char DeviceAddr, unsigned char RegisterAddr,unsigned char* pBuffer,unsigned int NumByte);
unsigned char I2C_ReadData(unsigned char Port,unsigned char Device,unsigned char Register,unsigned char* pBuffer,unsigned int NumByte);


i2c_interface UserI2c1 = {
    I2C_Init,
    I2C_ReadData,
    I2C_WriteData,
};

unsigned char PortSelect = 0;

/****************************************************************************************************************************
* @Functions:SCL_0()
* @Description:the SCL pin is set to 0.
* @Input:
* @Output:the level of the SCL is low.
* @Return:
* @Others:
* @History:
****************************************************************************************************************************/
void SCL_0(void)
{
    switch(PortSelect)
    {
    case 0:

        break;

    case 1:															//ADS1115
        HAL_GPIO_WritePin(ADS1115_I2C2_SCL_GPIO_Port, ADS1115_I2C2_SCL_Pin, GPIO_PIN_RESET);
        break;

    case 2:															//LIGHTNING
        HAL_GPIO_WritePin(LIGHTNING_I2C1_SCL_GPIO_Port, LIGHTNING_I2C1_SCL_Pin, GPIO_PIN_RESET);
        break;

    }
}

/****************************************************************************************************************************
* @Functions:SCL_1()
* @Description:the SCL pin is set to 1.
* @Input:
* @Output:the level of the SCL is high.
* @Return:
* @Others:
* @History:
****************************************************************************************************************************/
void SCL_1(void)
{
    switch(PortSelect)
    {
    case 0:

        break;

    case 1:															//ADS1115
        HAL_GPIO_WritePin(ADS1115_I2C2_SCL_GPIO_Port, ADS1115_I2C2_SCL_Pin, GPIO_PIN_SET);
        break;

    case 2:															//LIGHTNING
        HAL_GPIO_WritePin(LIGHTNING_I2C1_SCL_GPIO_Port, LIGHTNING_I2C1_SCL_Pin, GPIO_PIN_SET);
        break;

    }
}


/****************************************************************************************************************************
* @Functions:SDA_0()
* @Description:the SDA pin is set to 0.
* @Input:
* @Output:the level of the SDA is low.
* @Return:
* @Others:
* @History:
****************************************************************************************************************************/
void SDA_0(void)
{
    switch(PortSelect)
    {
    case 0:

        break;

    case 1:
        HAL_GPIO_WritePin(ADS1115_I2C2_SDA_GPIO_Port, ADS1115_I2C2_SDA_Pin, GPIO_PIN_RESET);
        break;

    case 2:
        HAL_GPIO_WritePin(LIGHTNING_I2C1_SDA_GPIO_Port, LIGHTNING_I2C1_SDA_Pin, GPIO_PIN_RESET);
        break;

    }
}


/****************************************************************************************************************************
* @Functions:SDA_1()
* @Description:the SDA pin is set to 1.
* @Input:
* @Output:the level of the SDA is high.
* @Return:
* @Others:
* @History:
****************************************************************************************************************************/
void SDA_1(void)
{
    switch(PortSelect)
    {
    case 0:

        break;

    case 1:
        HAL_GPIO_WritePin(ADS1115_I2C2_SDA_GPIO_Port, ADS1115_I2C2_SDA_Pin, GPIO_PIN_SET);
        break;

    case 2:
        HAL_GPIO_WritePin(LIGHTNING_I2C1_SDA_GPIO_Port, LIGHTNING_I2C1_SDA_Pin, GPIO_PIN_SET);
        break;

    }
}



/****************************************************************************************************************************
* @Functions:SDA_DATA()
* @Description:if or not the I2C slave has ACK.
* @Input:
* @Output:
* @Return:0:the I2C slave has ACK.
* @Others:
* @History:
****************************************************************************************************************************/
unsigned char SDA_DATA(void)
{
    unsigned int value;

    switch(PortSelect)
    {
    case 0:

        break;

    case 1:
        value=HAL_GPIO_ReadPin(ADS1115_I2C2_SDA_GPIO_Port, ADS1115_I2C2_SDA_Pin);
        break;

    case 2:
        value=HAL_GPIO_ReadPin(LIGHTNING_I2C1_SDA_GPIO_Port, LIGHTNING_I2C1_SDA_Pin);
        break;
    }
    if(value)
        return 1;
    else
        return 0;
}

/****************************************************************************************************************************
* @Functions:I2C_Init()
* @Description:the pins of the SCL and SDA are initialed
* @Input:
* @Output:
* @Return:
* @Others:
* @History:
****************************************************************************************************************************/
void I2C_Init(void)
{
//	GPIO_InitTypeDef GPIO_InitStruct;
//
//	GPIO_InitStruct.Pin = GPIO_PIN_8;																				//PB8  --> SCL    Push Pull Mode
//  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
//  GPIO_InitStruct.Pull = GPIO_NOPULL;
//  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
//  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
//
//	GPIO_InitStruct.Pin = GPIO_PIN_9;																				//PB9  --> SDA    Open Drain Mode
//  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
//  GPIO_InitStruct.Pull = GPIO_NOPULL;
//  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
//  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}


/****************************************************************************************************************************
* @Functions:I2C_Delay()
* @Description:delay for I2C
* @Input:
* @Output:
* @Return:
* @Others:
* @History:
****************************************************************************************************************************/
void I2C_Delay(void)
{
    unsigned char conut = 10;

    while(conut != 0)
    {
        conut--;
    }
}

/****************************************************************************************************************************
* @Functions:I2C_Start()
* @Description:be used in I2C
* @Input:
* @Output:
* @Return:
* @Others:
* @History:
****************************************************************************************************************************/
void I2C_Start(void)
{
    SDA_1();
    SCL_1();
    I2C_Delay();
    SDA_0();
    I2C_Delay();
    SCL_0();
    I2C_Delay();
}

/****************************************************************************************************************************
* @Functions:I2C_Stop()
* @Description:be used in I2C
* @Input:
* @Output:
* @Return:
* @Others:
* @History:
****************************************************************************************************************************/
void I2C_Stop(void)
{
    SDA_0();
    SCL_0();
    I2C_Delay();
    SCL_1();
    I2C_Delay();
    SDA_1();
    I2C_Delay();
}

/****************************************************************************************************************************
* @Functions:I2C_SendAck()
* @Description:when mcu master has received the data,it must send an ACK to slave and the SDA is low.
* @Input:
* @Output:
* @Return:
* @Others:
* @History:
****************************************************************************************************************************/
void I2C_SendAck(void)
{
    SDA_0();
    SCL_1();
    I2C_Delay();
    SCL_0();
    I2C_Delay();
}

/****************************************************************************************************************************
* @Functions:I2C_SendNoAck()
* @Description:when master send no ACK,the level of the SDA is high.
* @Input:
* @Output:
* @Return:
* @Others:
* @History:
****************************************************************************************************************************/
void I2C_SendNoAck(void)
{
    SDA_1();
    SCL_1();
    I2C_Delay();
    SCL_0();
    I2C_Delay();
}


/****************************************************************************************************************************
* @Functions:I2C_WaitAck()
* @Description:master must scan the ACK signal(the state of SDA) when master send a byte to slave.
* @Input:
* @Output:
* @Return:1:slave has ACK.
* @Others:
* @History:
****************************************************************************************************************************/
unsigned char I2C_WaitAck(void)
{
    uint8_t	count = 250;
    unsigned char Ack;

    SDA_1();
    SCL_1();
//	GPIO_I2C1_SDA_INPUT;
    I2C_Delay();
    Ack = SDA_DATA();
    while(Ack)
    {
        count--;
        Ack = SDA_DATA();
        if(count == 0)
        {
            SCL_0();
            I2C_Delay();
            return 0;
        }
    }
    SCL_0();
//	GPIO_I2C1_SDA_OUTPUT;
    I2C_Delay();
//	if(Ack)								//if I2C slave has ack,the ack level is low.       if I2C slave has no ack,the ack level is high.
//		return 0;

    return 1;
}



/****************************************************************************************************************************
* @Functions:I2C_SendByte()
* @Description:master send a byte to slave.
* @Input:data is sent.
* @Output:
* @Return:1:the data is sent successfully.
* @Others:
* @History:
****************************************************************************************************************************/
unsigned char I2C_SendByte(unsigned char dat)
{
    unsigned char i;

    for(i=0; i<8; i++)
    {
        if(dat & 0x80)
        {
            SDA_1();
        }
        else
        {
            SDA_0();
        }
        SCL_1();
        I2C_Delay();
        SCL_0();
        dat <<= 1;
        I2C_Delay();
    }
    return I2C_WaitAck();
}

/****************************************************************************************************************************
* @Functions:I2C_RcvDat()
* @Description:master read data from slave.
* @Input:the address of data which is used to save the read data from slave.
* @Output:
* @Return:
* @Others:
* @History:
****************************************************************************************************************************/
void I2C_RcvDat(unsigned char *pRdDat)
{
    unsigned char i;


    SDA_1();
//	GPIO_I2C1_SDA_INPUT;
    for(i=0; i<8; i++)
    {
        SCL_1();
        I2C_Delay();
        *pRdDat<<=1;
        if(SDA_DATA())
        {
            *pRdDat|=1;
        }
        SCL_0();
        I2C_Delay();
    }
//	GPIO_I2C1_SDA_OUTPUT;
}

/****************************************************************************************************************************
* @Functions:I2C_ReceiveBytes()
* @Description:master read many bytes from slave.It is used in I2C_ReadData().
* @Input:
	pBuffer:the address of the data which is read from slave.
	bytes:the number bytes of read data.
* @Output:
* @Return:
* @Others:
* @History:
****************************************************************************************************************************/
void I2C_ReceiveBytes(unsigned char *pBuffer,unsigned char bytes)
{
    unsigned char i;

    for(i=0; i<bytes; i++)
    {
        I2C_RcvDat(pBuffer+i);

        if(i==bytes-1)
        {
            I2C_SendNoAck();
        }
        else
        {
            I2C_SendAck();
        }
    }
}

/****************************************************************************************************************************
* @Functions:I2C_WriteData()
* @Description:master send data to slave
* @Input:
	DeviceAddr:the hardware address of the slave.
	RegisterAddr:the register address of the sent data in the slave.
	pBuffer:the address of the sent data in the mcu.
	NumByte:the number bytes of the sent data.
* @Output:
* @Return:
* @Others:
* @History:
****************************************************************************************************************************/
unsigned char I2C_WriteData(unsigned char Port,unsigned char DeviceAddr, unsigned char RegisterAddr,unsigned char* pBuffer,unsigned int NumByte)
{
    unsigned char ret = 0;
    unsigned char i;

    PortSelect = Port;

    I2C_Start();

    if(I2C_SendByte(DeviceAddr) == 0)
    {
        goto write_end;
    }
    if(I2C_SendByte(RegisterAddr) == 0)
    {
        goto write_end;
    }
    for(i=0; i<NumByte; i++)
    {
        if(I2C_SendByte(pBuffer[i]) == 0)
        {
            goto write_end;
        }
    }
    ret = 1;
write_end:
    I2C_Stop();
    return ret;
}

/****************************************************************************************************************************
* @Functions:I2C_ReadData()
* @Description:master read data from slave.
* @Input:
	DeviceAddr:the hardware address of the slave.
	RegisterAddr:the register address of the read data in the slave.
	pBuffer:the address of the read data in the mcu.
	NumByte:the number bytes of the read data.
* @Output:
* @Return:
* @Others:
* @History:
****************************************************************************************************************************/
unsigned char I2C_ReadData(unsigned char Port,unsigned char DeviceAddr, unsigned char RegisterAddr,unsigned char* pBuffer,unsigned int NumByte)
{
    unsigned char ret = 1;

    PortSelect = Port;

    I2C_Start();

    if(I2C_SendByte(DeviceAddr) == 0)
    {
        ret = 0;
        goto read_end;
    }
    if(I2C_SendByte(RegisterAddr) == 0)
    {
        ret = 0;
        goto read_end;
    }
    I2C_Start();
    if(I2C_SendByte(DeviceAddr|1) == 0)			//notes:DeviceAddr is writing address,then DeviceAddr|1 is read address.
    {
        ret = 0;
        goto read_end;
    }
    I2C_ReceiveBytes(pBuffer,NumByte);

read_end:
    I2C_Stop();
    return ret;
}




